/*************************************************************************** 
 * (c) 2006 Dmitry Osinovsky, osdmsoftware@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License as        *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 ***************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace OsdmSoftware.CommonLibrary
{
    public partial class ScrollBox: UserControl
    {
        bool centerControlIfSmall;

        public bool CenterControlIfSmall { get { return centerControlIfSmall; } set { centerControlIfSmall = value; } }

        IScrollableControl scrollableControl;

        public IScrollableControl ScrollableControl
        {
            get
            {
                return scrollableControl;
            }
            set
            {
                if (scrollableControl != value)
                {
                    scrollableControl = value;
                    if (scrollableControl != null)
                    {
                        scrollableControl.Control.Parent = this;
                        scrollableControl.Control.Top = 0;
                        scrollableControl.Control.Left = 0;
                        UpdateScrollBars();
                    }
                }
            }
        }

        public ScrollBox()
        {
            InitializeComponent();
            centerControlIfSmall = true;
        }

        protected override void OnResize(EventArgs e)
        {
            if (scrollableControl != null)
                UpdateScrollBars();
            base.OnResize(e);
        }

        void HideHScrollBar()
        {
            hScrollBar1.Visible = false;
            hScrollBar1.Maximum = scrollableControl.XLargeChange - 1;
            hScrollBar1.SmallChange = scrollableControl.XSmallChange;
            hScrollBar1.LargeChange = scrollableControl.XLargeChange;
            scrollableControl.Control.Height = Height;
            if (centerControlIfSmall)
                scrollableControl.XScroll = -(Width - vScrollBar1.Width - scrollableControl.XMaxScroll) / 2;
            else
                scrollableControl.XScroll = 0;
            vScrollBar1.Height = Height;
        }

        void HideVScrollBar()
        {
            vScrollBar1.Visible = false;
            vScrollBar1.Maximum = scrollableControl.YLargeChange - 1;
            vScrollBar1.SmallChange = scrollableControl.YSmallChange;
            vScrollBar1.LargeChange = scrollableControl.YLargeChange;
            scrollableControl.Control.Width = Width;
            if (centerControlIfSmall)
                scrollableControl.YScroll = -(Height - hScrollBar1.Height - scrollableControl.YMaxScroll) / 2;
            else
                scrollableControl.YScroll = 0;
            hScrollBar1.Width = Width;
        }

        void ShowHScrollBar()
        {
            hScrollBar1.Visible = true;
            scrollableControl.Control.Height = Height - hScrollBar1.Height;
            hScrollBar1.Minimum = 0;
            hScrollBar1.Maximum = scrollableControl.XMaxScroll - Width + vScrollBar1.Width + scrollableControl.XLargeChange + 5;
            hScrollBar1.SmallChange = scrollableControl.XSmallChange;
            hScrollBar1.LargeChange = scrollableControl.XLargeChange;
            if (scrollableControl.XScroll > scrollableControl.XMaxScroll - Width + vScrollBar1.Width)
            {
                scrollableControl.XScroll = scrollableControl.XMaxScroll - Width + vScrollBar1.Width - 1;
            }
            else if (scrollableControl.XScroll < 0)
                scrollableControl.XScroll = 0;

            hScrollBar1.Value = scrollableControl.XScroll;
            vScrollBar1.Height = Height - hScrollBar1.Height;
        }

        void ShowVScrollBar()
        {
            vScrollBar1.Visible = true;
            scrollableControl.Control.Width = Width - vScrollBar1.Width;
            vScrollBar1.Minimum = 0;
            vScrollBar1.Maximum = scrollableControl.YMaxScroll - Height + hScrollBar1.Height + scrollableControl.YLargeChange + 5;
            vScrollBar1.SmallChange = scrollableControl.YSmallChange;
            vScrollBar1.LargeChange = scrollableControl.YLargeChange;
            if (scrollableControl.YScroll > scrollableControl.YMaxScroll - Height + hScrollBar1.Height)
            {
                scrollableControl.YScroll = scrollableControl.YMaxScroll - Height + hScrollBar1.Height - 1;
            }
            else if (scrollableControl.YScroll < 0)
                scrollableControl.YScroll = 0;

            vScrollBar1.Value = scrollableControl.YScroll;
            hScrollBar1.Width = Width - vScrollBar1.Width;
        }

        public void UpdateScrollBars()
        {
            hScrollBar1.Location = new Point(0, Height - hScrollBar1.Height);
            vScrollBar1.Location = new Point(Width - vScrollBar1.Width, 0);
            if (scrollableControl.XMaxScroll < Width && scrollableControl.YMaxScroll < Height)
            {
                HideHScrollBar();
                HideVScrollBar();
            }
            else if (scrollableControl.XMaxScroll < Width - vScrollBar1.Width)
            {
                HideHScrollBar();
                ShowVScrollBar();
            }
            else if (scrollableControl.YMaxScroll < Height - hScrollBar1.Height)
            {
                ShowHScrollBar();
                HideVScrollBar();
            }
            else
            {
                ShowHScrollBar();
                ShowVScrollBar();
            }
        }

        private void vScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            if (scrollableControl != null && scrollableControl.YScroll != vScrollBar1.Value)
            {
                scrollableControl.YScroll = vScrollBar1.Value;
            }
        }

        private void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            if (scrollableControl != null && scrollableControl.XScroll != hScrollBar1.Value)
            {
                scrollableControl.XScroll = hScrollBar1.Value;
            }
        }

        public Point Position
        {
            get
            {
                if (scrollableControl != null)
                    return new Point(scrollableControl.XScroll, scrollableControl.YScroll);
                else
                    return new Point(0, 0);
            }
            set
            {
                if (value.X < 0)
                    hScrollBar1.Value = 0;
                else if (value.X > hScrollBar1.Maximum - hScrollBar1.LargeChange + 1)
                    hScrollBar1.Value = hScrollBar1.Maximum - hScrollBar1.LargeChange + 1;
                else
                    hScrollBar1.Value = value.X;
                if (value.Y < 0)
                    vScrollBar1.Value = 0;
                else if (value.Y > vScrollBar1.Maximum - vScrollBar1.LargeChange + 1)
                    vScrollBar1.Value = vScrollBar1.Maximum - vScrollBar1.LargeChange + 1;
                else
                    vScrollBar1.Value = value.Y;
            }
        }
    }

    public interface IScrollableControl
    {
        int XScroll { get; set; }
        int YScroll { get; set; }
        int XMaxScroll { get; }
        int YMaxScroll { get; }
        int XSmallChange { get; }
        int YSmallChange { get; }
        int XLargeChange { get; }
        int YLargeChange { get; }
        Control Control { get; }
    }
}
